package main

import (
	"log"
	"math/rand"
	"strconv"
	"sync"
	"time"
)

func main() {

	rand.Seed(time.Now().UnixNano())

	log.SetFlags(0)

	const Max = 100000
	const NumReceivers = 10
	const NumSenders = 1000

	var wgReceivers sync.WaitGroup
	wgReceivers.Add(NumReceivers)

	dataCh := make(chan int)
	stopCh := make(chan struct{})
	toStop := make(chan string)

	var stoppedBy string

	go func() {
		stoppedBy = <-toStop // 接收到停止信号，关闭 stopCh
		close(stopCh)
	}()
	// 多个生产者
	for i := 0; i < NumSenders; i++ {
		go func(id string) {

			for {
				value := rand.Intn(Max) // 生产出待发送数据
				if value == 0 {         // 此 id 对应的生产者要终止整个 程序
					select {
					case toStop <- "发送者#" + id:
					default:

					}
					return
				}

				select {
				case <-stopCh: // 接收到退出信号
					return
				default:

				}

				select {
				case <-stopCh:
					return
				case dataCh <- value:
				}

			}

		}(strconv.Itoa(i))
	}
	// 多个消费者
	for i := 0; i < NumReceivers; i++ {
		go func(id string) {

			defer wgReceivers.Done()
			for {
				select {
				case <-stopCh:
					return
				default:

				}
				select {
				case <-stopCh:
					return
				case value := <-dataCh:
					if value == Max-1 { // 如果从生产者接收到的数据 == max-1 则退出整个程序
						select {
						case toStop <- "接收者#" + id:
						default:

						}
						return
					}
					log.Println(value)
				}
			}

		}(strconv.Itoa(i))
	}
	wgReceivers.Wait()
	log.Printf("被" + stoppedBy + "终止了！")

}
